﻿using System;
using System.Data;
using System.Data.Common;
using System.Configuration;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using Vbyte.SharpOrm.Config;
using Vbyte.SharpOrm.SqlDb;
using Vbyte.SharpOrm.Adapter;

namespace Vbyte.SharpOrm
{
    /// <summary>
    /// 对各个ADO.NET提供者的适配器
    /// </summary>
    public class AdoNetAdapter : IDisposable
    {
        /// <summary>
        /// 初始化ADO.NET的ORM适配器<see cref="AdoNetAdapter"/>
        /// </summary>
        /// <param name="connName">连接字符串名称</param>
        public AdoNetAdapter(string connName)
        {
            InitializeByConnKey(connName);
        }

        /// <summary>
        /// 初始化ADO.NET的ORM适配器
        /// </summary>
        /// <param name="SqlTableEntry">数据库映射实例</param>
        public AdoNetAdapter(TableEntry SqlTableEntry)
        { 
            Type t = SqlTableEntry.GetType();
            object[] attrs = t.GetCustomAttributes(typeof(BindTableAttribute), true);
            if (attrs == null || attrs.Length == 0)
            {
                throw new InvalidOperationException("指定对象没有配置BindTableAttribute属性！");
            }
            else
            {
                _currentTableBind = attrs[0] as BindTableAttribute;

                InitializeByConnKey(_currentTableBind.BindConnectionKey);
            }
        }

        /// <summary>
        /// 数据提供者缓存词典
        /// </summary>
        static Dictionary<string, DbProviderFactory> FactoryCache = new Dictionary<string, DbProviderFactory>();


        private string _connKey = null;
        /// <summary>
        /// 当前实例应用到的连接字符串键名
        /// </summary>
        public string ConnectionKey
        {
            get { return _connKey; }
            set { _connKey = value; }
        }

        private void InitializeByConnKey(string connKey)
        {
            ConnectionStringSettings connSetting = ConfigurationManager.ConnectionStrings[connKey];
            if (connSetting == null)
                throw new InvalidProgramException("指定名称为 [" + connKey + "] 的连接字符串不存在！");

            ConnectionKey = connKey;

            _providerName = connSetting.ProviderName;
            _connectionString = connSetting.ConnectionString;

            string cacheKey = _providerName.ToLowerInvariant();
            if (FactoryCache.ContainsKey(cacheKey))
            {
                factory = FactoryCache[cacheKey] as DbProviderFactory;
            }
            else
            {
                //检查是否已知的ProviderName
                factory = DbProviderFactories.GetFactory(_providerName);
                if (factory == null)
                {
                    throw new NotSupportedException("配置错误：没有找到提供者为" + _providerName +
                        @"的数据工厂，该提供者不受支持！");
                }
                FactoryCache.Add(cacheKey, factory);
            }
        }

        private BindTableAttribute _currentTableBind;
        /// <summary>
        /// 当前适配器的数据表绑定设置
        /// </summary>
        /// <returns></returns>
        public BindTableAttribute GetTableBindConfig()
        {
            return _currentTableBind;
        }

        /*
        // for NET 1.1
        // AdoNetProviderCollection providers = (AdoNetProviderCollection)ConfigurationSettings.GetConfig("AdoNetProvider");
        // ----
           AdoNetProviderCollection providers = (AdoNetProviderCollection)ConfigurationManager.GetSection("AdoNetProvider");
         */

        private string _providerName;
        /// <summary>
        /// ADO.NET数据源提供者名称
        /// </summary>
        public string ProviderName
        {
            get { return _providerName; }
        }

        private string _connectionString;

        /// <summary>
        /// 获取连接对象的连接字符串
        /// </summary>
        public string ConnectionString
        {
            get { return _connectionString; }
        }

        #region ADO.NET内部支持
        private DbCommand _dbCmd;
        /// <summary>
        /// 表示要对数据源执行的 SQL 语句或存储过程。
        /// </summary>
        /// <returns></returns>
        public DbCommand GetDbCommand()
        {
            if (_dbCmd == null) _dbCmd = factory.CreateCommand();
            return _dbCmd;
        }

        private DbConnection _dbConn;
        /// <summary>
        /// 表示到数据库的连接
        /// </summary>
        /// <returns></returns>
        public DbConnection GetDbConnection()
        {
            if (_dbConn == null)
            {
                _dbConn = factory.CreateConnection();
                _dbConn.ConnectionString = _connectionString;
            }
            return _dbConn;
        }

        private DbDataAdapter _dbAdapater;
        /// <summary>
        /// 帮助实现 System.Data.IDbDataAdapter 接口。System.Data.Common.DbDataAdapter 的继承者实现一组函数以提供强类型，
        /// 但是继承了完全实现DataAdapter 所需的大部分功能。
        /// </summary>
        /// <returns></returns>
        public DbDataAdapter GetDbDataAdapter()
        {
            if (_dbAdapater == null) _dbAdapater = factory.CreateDataAdapter();
            return _dbAdapater;
        }

        /*     
        Name | Description | InvariantName | AssemblyQualifiedName
        Odbc Data Provider | .Net Framework Data Provider for Odbc | System.Data.Odbc | System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        OleDb Data Provider | .Net Framework Data Provider for OleDb | System.Data.OleDb | System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        OracleClient Data Provider | .Net Framework Data Provider for Oracle | System.Data.OracleClient | System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        SqlClient Data Provider | .Net Framework Data Provider for SqlServer | System.Data.SqlClient | System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        Microsoft SQL Server Compact Data Provider | .NET Framework Data Provider for Microsoft SQL Server Compact | System.Data.SqlServerCe.3.5 | System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=3.5.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91
        VistaDB Data Provider | .Net Framework Data Provider for VistaDb | VistaDB.NET20 | VistaDB.Provider.VistaDBProviderFactory, VistaDB.NET20, Version=3.3.1.54, Culture=neutral, PublicKeyToken=dfc935afe2125461
        */
        private DbProviderFactory factory = null;

        /// <summary>
        /// 获取提供程序对数据源类的实现的实例
        /// </summary>
        /// <returns></returns>
        public DbProviderFactory GetDbProviderFactory()
        {
            //Type tFactory = Type.GetType(typeof(System.Data.Odbc.OdbcFactory).AssemblyQualifiedName,
            //    true, true);
            //FieldInfo instance = tFactory.GetField("Instance", BindingFlags.Static | BindingFlags.Public);
            //Assert.IsNotNull(instance);
            return factory;

        } 
        #endregion

        #region 建(删)表支持
        /// <summary>
        /// 根据实体配置，自动建立数据库相关表。
        /// </summary>
        /// <param name="entry">映射实例</param>
        public static void CreateTable(TableEntry entry)
        {
            AdoNetAdapter adp = new AdoNetAdapter(entry);
            using (ISqlDb db = adp.GetSqlDbHelper())
            {
                db.CreateTable(entry.GetSqlTableDefine());
            }
            adp.Dispose();

        }

        /// <summary>
        ///  删除实例映射数据库表
        /// </summary>
        /// <param name="entry">映射实例</param>
        public static void DropTable(TableEntry entry)
        {
            AdoNetAdapter adp = new AdoNetAdapter(entry);
            using (ISqlDb db = adp.GetSqlDbHelper())
            {
                SqlTable tab = entry.GetSqlTableDefine();
                db.DropTable(tab.Name);
            }
            adp.Dispose();
        }
        #endregion

        /// <summary>
        /// 获取相关SQL数据库的辅助
        /// </summary>
        /// <returns>数据库(表)创建维护辅助</returns>
        public ISqlDb GetSqlDbHelper()
        {
            if (string.Compare(ProviderName, "System.Data.SqlClient", true) == 0)
            {
                return new SqlServer(ConnectionString);
            }
            else if (string.Compare(ProviderName, "System.Data.OleDb", true) == 0)
            {
                return new Access(ConnectionString);
            }
            else
            {
                return GetAdapaterInstance<ISqlDb>((i, key) => ProviderConfig.GetSqlDb(i.DbType, key));
            }
        }

        /// <summary>
        /// 针对特定数据库实现的数据库适配
        /// </summary>
        /// <returns>数据操作差异适配</returns>
        public ISqlDbAdapter GetSqlDbAdapter()
        {
            if (string.Compare(ProviderName, "System.Data.SqlClient", true) == 0)
            {
                return new SqlServerAdapter();
            }
            else if (string.Compare(ProviderName, "System.Data.OleDb", true) == 0)
            {
                return new AccessAdapter();
            }
            else
            {
                return GetAdapaterInstance<ISqlDbAdapter>((i, key) => ProviderConfig.GetSqlAdapter(i.AdapterType, key));
            }
        }

        /// <summary>
        /// 实例约束实现适配，默认为<c>Vbyte.SharpOrm.SqlDb.SqlNativeConstrains</c>。
        /// </summary>
        /// <returns>实例约束实现适配</returns>
        public ISqlConstrains GetSqlConstrains()
        {
            if (string.Compare(ProviderName, "System.Data.SqlClient", true) == 0)
            {
                return new SqlNativeConstrains();
            }
            else if (string.Compare(ProviderName, "System.Data.OleDb", true) == 0)
            {
                return new SqlNativeConstrains();
            }
            else
            {
                return GetAdapaterInstance<ISqlConstrains>( (i,key) => ProviderConfig.GetSqlConstrains(i.ConstrainsType, key) );
            }
        }

        /// <summary>
        /// 获取当前应用实例的SQL构建适配
        /// </summary>
        /// <returns>构建SQL语句适配</returns>
        public ISqlBuilderAdapter GetSqlBuilder()
        {
            if (string.Compare(ProviderName, "System.Data.SqlClient", true) == 0)
            {
                return new MsSqlBuilderAdapter();
            }
            else if (string.Compare(ProviderName, "System.Data.OleDb", true) == 0)
            {
                return new JetSqlBuilderAdapter();
            }
            else
            {
                return GetAdapaterInstance<ISqlBuilderAdapter>((i, key) => ProviderConfig.GetSqlBuilder(i.BuilderType, key));
            }
        }

        private T GetAdapaterInstance<T>(Func<OrmImplement, string , T> GetFun)
        {
            OrmImplement[] imps = ProviderConfig.ConfigInstance.Implements;
            if (imps != null && imps.Length > 0)
            {
                for (int i = 0; i < imps.Length; i++)
                {
                    if (!string.IsNullOrEmpty(imps[i].ApplyKey) && string.Equals(ConnectionKey, imps[i].ApplyKey, StringComparison.InvariantCultureIgnoreCase))
                    {
                        return GetFun(imps[i], ConnectionKey);
                    }
                    else
                    {
                        if (string.Compare(ProviderName, imps[i].ProviderName, true) == 0)
                        {
                            return GetFun(imps[i], String.Empty);
                        }
                    }
                }
            }
            return default(T);
        }

        #region IDisposable 成员

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
        /// </summary>
        public void Dispose()
        {
            
        }

        #endregion
    }

}
